/* app_lwip_tcp_server.c */

#include "app_inc.h"

/*******************************************************************************
 * Definitions
 ******************************************************************************/

/*******************************************************************************
 * Variables
 ******************************************************************************/

/*******************************************************************************
 * Prototypes
 ******************************************************************************/
/* 这里作为参数传入函数的函数指针, 其类型都是由lwip预先定义好了,
 * 用户可以遵循lwip定义好的流程想方设法拿到消息数据或者发送数据.
 */
static err_t app_lwip_server_accept(void *arg, struct tcp_pcb *pcb, err_t err);
static err_t app_lwip_server_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err);

/*******************************************************************************
 * Code
 ******************************************************************************/


void  app_lwip_tcp_server_init(void)
{
    /* 新建控制块 */
    struct tcp_pcb * pcb = tcp_new();

    /* 将pcb控制块绑定一个端口, 已接受客户端的连接.
     * 使用IP_ADDR_ANY作为pcb控制块的ip地址, 意味着这个pcb可以给任何本地的接口使用.
     */
    tcp_bind(pcb, IP_ADDR_ANY, 6060);

    /* Set the connection to the LISTEN state */
    pcb = tcp_listen(pcb);

    /* 向lwip注册回调函数,
     * 当server建立好一个连接后, lwip会自动调用用户指定的app_lwip_server_accept()函数处理消息数据. */
    tcp_accept(pcb, app_lwip_server_accept);
}

/* server建立连接后执行的用户回调函数.
 * 本例中直接将建立连接的pcb传入tcp_recv()函数执行一些lwip接收数据的标准操作,
 * 然后进一步调用app_lwip_server_recv()函数处理消息数据.
 */
static err_t app_lwip_server_accept(void *arg, struct tcp_pcb *pcb, err_t err)
{
    tcp_recv(pcb, app_lwip_server_recv);

    return ERR_OK;
}

/* 提取收到的消息数据, 根据用户需求自行处理.
 * p指向的pbuf链中包含了消息数据内容.
 */
static err_t app_lwip_server_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
{
    char *data_recv = NULL;
    int index = 0;
    struct pbuf *q = NULL;

    /* We perform here any necessary processing on the pbuf */
    if (p != NULL)
    {
        data_recv = (char *)mem_calloc(p->tot_len + 1, 1); /* 多的1个字节存放的是'\0', 作为字符串的结尾符. */
        if (NULL == data_recv)
        {
            printf("[Server]mem_calloc error, len = %u\r\n", p->tot_len);
        }
        else
        {
            /* 把pbuf链中的数据内容复制到一块连续的内存区中. */
            q = p;
            while(q != NULL)
            {
                memcpy(&data_recv[index],q->payload,q->len);
                index += q->len;
                q = q->next;
            }

            /* 再次插入用户程序在tcp server收到数据有的处理过程. */
            printf("[Server]Get MSG: %s\r\n", data_recv);

            /* 释放内存空间 */
            mem_free(data_recv);
            data_recv = NULL;
        }

        tcp_recved(pcb, p->tot_len); /* 移动tcp的接收窗口, 用以接收新的ip数据包. */
        pbuf_free(p);
    }
    else if (err == ERR_OK)
    {
        /* When the pbuf is NULL and the err is ERR_OK, the remote end is closing the connection. */
        /* then we should free the allocated memory and close the connection */
        return tcp_close(pcb);
    }
    return ERR_OK;
}

/* EOF. */

